
// === uuAjax ===
// depend: uuMeta, uuURL
/*
uuAjax(url, ok = undef, param = { header, ifmod, data, ng })
uuAjax.sync(url) - return response text or ""
uuAjax.create() - return XHR object
 */
(function() {
var _ajax, // inner namespace
    _mm = uuMeta,
    _win = window,
    _ie = _mm.ie,
    _mix = _mm.mix,
    _cache = {}; // Ajax: If-Modified-Since cache

// uuAjax - Async request
_ajax = function(url,     // @param String: request url
                 ok,      // @param Function(= undefined): callback function
                 param) { // @param Hash(= undefined): param
  url = uuURL.abs(url);
  param = param || {};

  var xhr, run = 0, i, gmt,
      header = param.header || { "X-Requested-With": "XMLHttpRequest" },
      ifmod = param.ifmod,
      data = param.data,
      ng = param.ng;

  function state() {
    if (xhr.readyState === 4) {
      if (xhr.status === 200 || !xhr.status) {
        (ok && !run++) && ok(xhr.responseText, url);
        if (ifmod) { // parse "Last-Modified" value
          var last = xhr.getResponseHeader("Last-Modified");
          _cache[url] = last ? Date.parse(last) : 0;
        }
        return;
      }
      (ng && !run++) && ng(xhr.status, url); // 304 too
    }
  }

  if ( (xhr = this.create()) ) {
    try {
      xhr.onreadystatechange = state;
      xhr.open(data ? "POST" : "GET", url.replace(/&amp;/g, "&"), true);

      if (ifmod && url in _cache) {
        gmt = (new Date(_cache[url])).toUTCString();
        if (/UTC/.test(gmt)) {
          gmt = gmt.replace(/UTC/, "GMT");
          (gmt.length < 29) && (gmt = gmt.replace(/, /, ", 0"));
        }
        header["If-Modified-Since"] = gmt; // "Thu, 01 Jan 1970 00:00:00 GMT"
      }
      data && (header["Content-Type"] = "application/x-www-form-urlencoded");
      for (i in header) {
        xhr.setRequestHeader(i, header[i]);
      }
      xhr.send(data || null);

      setTimeout(function() { // watchdog timer
        xhr.abort();
        (ng && !run++) && ng(408, url); // 408 "Request Time-out"
      }, param.timeout || 10000);
      return;
    } catch (err) {}
  }
  (ng && !run++) && ng(400, url);
};

_mix(_ajax, {
  // uuAjax.sync - Sync "GET" request
  sync: function(url) { // @param String: request url
                        // @return String: responseText or ""
    try {
      var xhr = this.create();
      xhr.open("GET", uuURL.abs(url).replace(/&amp;/g, "&"), false); // sync
      xhr.send(null);
      if (xhr.status === 200 || !xhr.status) {
        return xhr.responseText;
      }
    } catch(err) {}
    return "";
  },

  // uuAjax.create - create XMLHttpRequest object
  create: function() {
    var rv;
    try {
      if (_ie && ActiveXObject) {
        rv = new ActiveXObject("Microsoft.XMLHTTP");
      }
      if (!rv && XMLHttpRequest) {
        rv = new XMLHttpRequest();
      }
    } catch (err) {}
    return rv;
  }
});

// --- initialize ---

// --- export ---
_win.uuAjax = _ajax; // window.uuAjax

})(); // uuAjax scope
